#include <stdio.h>
#include <hash_map>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
#include <queue>
#include "hse_common.h"
#include "tokenizer.h"

using namespace std;
using namespace stdext;

#define O(x) (x)


class MyData {
public:
	explicit MyData(int value) 
		: value_(value) {
		O(printf("construct from value %d\n", value));
	}

	inline public int Value() const {
		return value_;
	}

	/*
	 * for vector sort
	 */
	inline static bool SortCompare(const MyData* d1, const MyData* d2) {
		return d1->Value() < d2->Value();
	}

	static class Less : public binary_function<MyData*, MyData*, bool> {
	public:
		bool operator()(const MyData* left, const MyData* right) const{
			return SortCompare(left, right);
		}
	};

	static class More : public binary_function<MyData*, MyData*, bool> {
	public:
		bool operator()(const MyData* left, const MyData* right) const{
			return !SortCompare(left, right);
		}
	};

	static class HashCompare : public hash_compare<MyData *> {
	public:
		inline size_t operator()(const MyData* d) const {
			return (size_t) d->Value();
		}

		inline bool operator()(const MyData *d1, MyData *d2) const {
			return d1->Value() < d2->Value();
		}
	};

	void operator=(const MyData& right) {
		cout << "Assign from:" << right.value_ << endl;
		this->value_ = right.value_;
	}

	MyData(const MyData& another) {
		cout << "Copy construct from:" << another.value_ ;
		printf(", my address is:%d\n", this);
		this->value_ = another.value_;
	}

	~MyData() {
		O(cout << "Destruct with value:" << value_ << endl);
	}

private:
	int value_;

	//DISALLOW_COPY_AND_ASSIGN(MyData);
};

typedef MyData* MyDataPtr;

void test_sort() {
	vector<MyData*> v;
	MyData d1(1);
	MyData d2(5);
	MyData d3(3);
	v.push_back(&d1);
	v.push_back(&d2);
	v.push_back(&d3);
	std::sort(v.begin(), v.end(), MyData::SortCompare);
	for(unsigned int i = 0; i < v.size(); i++) 
		cout << v[i]->Value() << ",";
	cout << endl;
}

void test_hash_map() {
	hash_map<MyData*, int, MyData::HashCompare> m;
	MyData d1(1);
	MyData d2(5);
	MyData d3(3);
	m[&d1] = 1;
	m[&d2] = 5;
	m[&d3] = 3;
	MyData d(5);
	cout << m[&d] << endl;
}

void test_map() {
	map<MyData*, int, MyData::Less> m;
	MyData d1(1);
	MyData d2(5);
	MyData d3(3);
	m[&d1] = 1;
	m[&d2] = 5;
	m[&d3] = 3;
	map<MyData*, int, MyData::Less>::iterator i = m.begin();
	while (i != m.end()) {
		cout << i->first->Value() << ", " << i->second << endl;
		i++;
	}
}

void test_set() {
	set<MyData*, MyData::Less> s;
	MyData d1(1);
	MyData d2(5);
	MyData d3(3);
	s.insert(&d1);
	s.insert(&d2);
	s.insert(&d3);
	set<MyData*, MyData::Less>::iterator i = s.begin();
	while(i != s.end()) {
		cout << (*i)->Value() << ", ";
		i++;
	}
	cout << endl;
}

//test return
MyData f1() {
	MyData m(1);
	return m;
}

void test_return() {
	MyData m = f1();
	printf("Return object address is:%d\n", &m);
	char *c = new char[100];
	memset(c, 0, 100);
	cout << "Now m value is:" << m.Value() << endl;
}
//test reutnr end


void test_priority_queue() {
	priority_queue<MyData*, vector<MyData*>, MyData::More> q;
	MyData d1(1);
	MyData d2(5);
	MyData d3(3);
	q.push(&d1);
	cout << q.top()->Value() << endl;
	q.push(&d2);
	cout << q.top()->Value() << endl;
	q.push(&d3);
	cout << q.top()->Value() << endl;
	q.pop();
	cout << q.top()->Value() << endl;
}

void test_file_write() {
	unsigned char *buffer = new unsigned char[4096];
	memset(buffer, 0, 4096);
	for (unsigned int i = 0; i <= 255U; ++i) {
		cout << i;
		buffer[i] = i;
	}
	FILE *f = fopen("D:\\test.txt", "wb");
	int l = fwrite(buffer, 1, 4000, f);
	fclose(f);
	cout << "write " << l << " bytes to file!" << endl;
	delete[] buffer;
}

void test_file_read() {
	char *buffer = new char[4096 * 1024 * 2];
	FILE *f = fopen("D:\\test.txt", "rb");
	int l = fread(buffer, 1, 4096 * 1024 * 2, f);
	fclose(f);
	cout << "read " << l << " bytes from file!" << endl;
	delete[] buffer;
}

void test_file() {
	test_file_write();
	test_file_read();
}

void test_string_find() {
	hse::Tokenizer::Init();
	vector<string> terms;
	//computer abstract same way that
	terms.push_back("abstract");
	terms.push_back("same");
	terms.push_back("way");
	terms.push_back("that");
	terms.push_back("computer");
	
	string content("computer is concerned, this");
	cout << hse::string_term_em(content, terms) << endl;
}

int main2() {
	test_string_find();
	return 0;
}